package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *  动态代理：在内存中形成代理类
 * 	* 实现步骤：
 * 		1. 代理对象和真实对象实现相同的接口
 * 		2. 代理对象 = Proxy.newProxyInstance();
 * 		3. 使用代理对象调用方法。
 * 		4. 增强方法
 * 	* 增强方式：
 * 		1. 增强参数列表
 * 		2. 增强返回值类型
 * 		3. 增强方法体执行逻辑
 *
 *  该案例表示代理商和联想公司之间的关系，从代理商购买笔记本，实质还是从联想公司进行购买，实际调用的方法还是联想公司的
 *  只不过，在联想公司的方法基础之上进行改变
 *
 * @author Mc.Chai
 * @program: JavaWeb
 * @create 2022-04-08-16:30 16:30
 */
public class ProxyTest {
    public static void main(String[] args) {
        //真实的对象
        Lenovo lenovo = new Lenovo();
        /**
         * 创建代理对象
         *  三个参数：
         *       1.类加载器：真实对象.getClass().getClassLoader()
         *       2.接口数组：真实对象.getClass().getClassLoader()。
         *       3.处理器： new InvocationHandler()
         * 因为实现共同的接口，所有使用该类的接口类型（SaleComputer）
         * */
        SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
            /**
             * 代理逻辑编写的方法：代理对象调用的所有方法都会触发该方法执行
             * 参数：
             *  1.proxy:代理对象
             *  2.method:代理对象调用的方法，被封装为的对象
             *  3.args:代理对象调用的方法时，传递的实际参数
             *
             * */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /*System.out.println("该方法被执行");
                System.out.println(method.getName());*/
                //判断是否sale方法，1.防止空指针异常 2. 对不同的方法进行改造
                if (method.getName().equals("sale")){
                    //进行参数的增强
                    double money= (double) args[0]*0.85;
                    //执行Lenovo中的方法
                    Object invoke = method.invoke(lenovo, money);
                    //进行返回值的增强
                    return invoke+"+电脑包";
                }else{
                    Object invoke = method.invoke(lenovo);
                    return invoke;
                }



            }
        });
        //调用方法
        String sale = proxy_lenovo.sale(8000);
        System.out.println(sale);

        proxy_lenovo.show();
    }
}
